﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Security.Cryptography;
using System.Text;
using Castle.ActiveRecord;

namespace WebConversion.Module.MemberShip
{
    [ActiveRecord]
    public class UserProfile : ActiveRecordBase<UserProfile>
    {
        #region properties
        [PrimaryKey(PrimaryKeyType.Identity, "UserId")]
        public int UserId { get; set; }
        [Property]
        public string EMail { get; set; }
        [Property]
        public string GUID { get; set; }
        [Property]
        public string FirstName { get; set; }
        [Property]
        public string LastName { get; set; }
        [Property]
        public string Password { get; set; }
        [Property]
        public string Address { get; set; }
        #endregion

        public override void Create()
        {
            ValidateNewUser();
            ConvertNewUser();
            base.CreateAndFlush();
        }

        private void ConvertNewUser()
        {
            GUID = Guid.NewGuid().ToString();
            Password = GetMD5Hash(Password);
        }

        private void ValidateNewUser()
        {
            if (string.IsNullOrEmpty(FirstName)
                || string.IsNullOrEmpty(LastName)
                || string.IsNullOrEmpty(EMail)
                || string.IsNullOrEmpty(Password)
                )
            {
                throw new NoNullAllowedException("incomplete register information");
            }
        }

        public static bool ValidUser(string eMail, string password)
        {
            var conditions =
                new List<KeyValuePair<string, object>>
                    {
                        new KeyValuePair<string, object>("EMail", eMail),
                        new KeyValuePair<string, object>("Password", GetMD5Hash(password))
                    };
            var userProfiles = Repository.Find<UserProfile>(conditions);

            return userProfiles.Count == 1;
        }

        public static UserProfile GetUserByEMail(string eMail)
        {
            var condision = new KeyValuePair<string, object>("EMail", eMail);
            var userProfiles = Repository.Find<UserProfile>(condision);

            if (userProfiles.Count != 1)
            {
                throw new NotFoundException(
                        string.Format("can not find user by provided e-mail:{0}", eMail)
                    );
            }

            return userProfiles[0];
        }

        public static UserProfile GetUserByGuid(string guid)
        {
            var condision = new KeyValuePair<string, object>("GUID", guid);
            var userProfiles = Repository.Find<UserProfile>(condision);

            if (userProfiles.Count != 1)
            {
                throw new NotFoundException(
                        string.Format("can not find user by provided GUID:{0}", guid)
                    );
            }

            return userProfiles[0];
        }

        public static bool IsRegisted(string eMail)
        {
            var condision = new KeyValuePair<string, object>("EMail", eMail);
            var userProfiles = Repository.Find<UserProfile>(condision);

            return userProfiles.Count > 0;
        }

        #region password
        public static string GetMD5Hash(string input)
        {
            var md5Hasher = MD5.Create();
            var data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
            var builder = new StringBuilder();
            for (var i = 0; i < data.Length; i++)
            {
                builder.Append(data[i].ToString("x2"));
            }
            return builder.ToString();
        }

        public static bool VerifyMd5Hash(string input, string hash)
        {
            var hashOfInput = GetMD5Hash(input);
            var comparer = StringComparer.OrdinalIgnoreCase;

            return comparer.Compare(hashOfInput, hash) == 0;
        }

        public static bool ChangePassword(string guid, string oldPassword, string newPassword)
        {
            var userProfile = GetUserByGuid(guid);
            if(!ValidUser(userProfile.EMail, oldPassword))
            {
                throw new MemberAccessException();
            }

            userProfile.Password = GetMD5Hash(newPassword);
            userProfile.SaveAndFlush();

            return true;
        }
        #endregion
    }
}
